package com.telenav.comm;

import java.io.InputStream;
import java.io.OutputStream;

import com.telenav.network.SocketConnection;

abstract class SocketStreamHandler
{
    public static boolean handle(SocketConnection socketConnection, RequestJob job)
    {
        return handleStandaloneSocket(socketConnection, job);
    }
    
    private static boolean handleStandaloneSocket(SocketConnection socketConnection, RequestJob job)
    {
        OutputStream os = null;
        InputStream is = null;
        try
        {            
            if (job.response.isCanceled)
                return false;

            os = socketConnection.openOutputStream();
            job.os = os;

            if(job.response.requestData != null)
            {
                int contentLen = job.response.requestData.length;
    
                String sb = "POST " + "/" + " HTTP/1.1\n" + "Host: "
                        + job.host.host + "\n" + "Content-Length: " + contentLen
                        + "\n\n";
    
                byte[] header = sb.getBytes();
    
                os.write(header);
                os.write(job.response.requestData);
            }
        }
        catch (Throwable e)
        {
            job.response.errorMessage = e.getMessage();
            return false;
        }
        
        try
        {
            if (job.response.isCanceled)
                return false;

            is = socketConnection.openInputStream();
            if (is != null)
            {
                job.is = is;
                
                try
                {
                    return readStandAlone(is, job);
                }
                catch (Throwable e)
                {                  
                    job.response.errorMessage = e.getMessage();
                    return false;
                }
            }
            else
            {
                job.response.status = ICommCallback.RESPONSE_ERROR;
                job.response.errorMessage = socketConnection.toString();
            }
        }
        catch (Throwable e)
        {
            job.response.errorMessage = e.getMessage();
            return false;
        }
        
        return true;
    }
    
    private static boolean readStandAlone(InputStream is, RequestJob job) throws Exception
    {
        StringBuffer buff = new StringBuffer();
        String LEN_TOK = "Content-Length:";

        StringBuffer strLen = new StringBuffer();
        boolean isLen = false;
        boolean isDigit = false;

        int index = 0;
        int len = 0;
        int counter = 0;
        int emptyLineCounter = 0;

        while (true)
        {
            int n = is.read();

            if (n == -1)
            {
                return false;
            }

            char ch = (char) n;

            counter++;
            buff.append(ch);

            if (isLen)
            {
                if (Character.isDigit(ch))
                {
                    isDigit = true;
                    strLen.append(ch);
                }
                else
                {
                    if (isDigit)
                    {
                        if (n == 10)
                        {
                            emptyLineCounter++;
                        }
                        else
                        {
                            if (n != 13)
                                emptyLineCounter = 0;
                        }
                        if (emptyLineCounter == 2)
                            break;
                    }
                }
            }
            else
            {
                if (ch == LEN_TOK.charAt(index))
                {
                    index++;
                }
                else
                {
                    index = 0;
                }

                if (index == LEN_TOK.length())
                {
                    isLen = true;
                }
            }
        }

        // check for 200 OK
        if (buff.toString().indexOf("200 OK") == -1)
        {
            return false;
        }
        len = Integer.parseInt(strLen.toString().trim());

        return readContent(is, len, job);
    }

    protected static int readBytes(InputStream is, byte[] buff, int offset, int len) throws Exception
    {
        int bytesRead = 0;
        int MAX_CHUNK = 4096 * 8;
        while (bytesRead < len)
        {
            int nextChunk = len - bytesRead;
            if (nextChunk > MAX_CHUNK)
                nextChunk = MAX_CHUNK;
            int count = is.read(buff, offset, nextChunk);

            if (count < 0)
                break;
            bytesRead += count;
            offset += count;
        }
        return bytesRead;
    }
    
    

    private static void writeLongLive(OutputStream os, byte[] buff) throws Exception
    {
        // header - length
        int x = buff.length;

        // [XR]: the highest byte is the protocol flag
        // x x x x x x 1 1 (bit sequence from high to low)
        // if bit 0 == 1: UTF-8 encoding protocol
        // if bit 1 == 1: attach time stamp after total length
        x |= 0x03000000;

        // write length and flag
        for (int i = 0; i < 4; i++)
        {
            int b = x & 0xFF;
            os.write(b);
            x >>= 8;
        }

        // write timestamp
        long timestamp = System.currentTimeMillis();
        for (int i = 0; i < 8; i++)
        {
            int b = (int) timestamp & 0xFF;
            os.write(b);
            timestamp >>= 8;
        }

        os.write(buff);
        os.flush();
    }

    protected static boolean readContent(InputStream is, int len, RequestJob job) throws Exception
    {
        if (len == -1)
            return false;

        //job.response.responseData = data;

        if (job.response.isCanceled)
            return false;

        if (job.commCallBack != null)
        {
            job.commCallBack.handleChild(job.response);
        }
        
        if (job.response.isCanceled)
            return false;

        return true;
    }
}
